package backpropagation;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Random;

public class Main {

	static ArrayList<Double> identidad(ArrayList<ArrayList<Double>> ejs) {
		ArrayList<Double> salidas = new ArrayList();
		for (int i = 0; i < ejs.size(); i++) {
			salidas.add(ejs.get(i).get(0));
		}
		return salidas;
	}

	static ArrayList<Double> xala4(ArrayList<ArrayList<Double>> ejs) {
		ArrayList<Double> salidas = new ArrayList();
		for (int i = 0; i < ejs.size(); i++) {
			salidas.add(ejs.get(i).get(0) * ejs.get(i).get(0) * ejs.get(i).get(0) * ejs.get(i).get(0));
		}
		return salidas;
	}

	static ArrayList<Double> funcSeno(ArrayList<ArrayList<Double>> ejs) {
		ArrayList<Double> salidas = new ArrayList();
		for (int i = 0; i < ejs.size(); i++) {
			double res = Math.sin(ejs.get(i).get(0) * (5 * Math.PI / 2));
			salidas.add(res);
		}
		return salidas;
	}

	static ArrayList<ArrayList<Double>> crearEjemplos(int cantEjemplos) {
		ArrayList<ArrayList<Double>> ejs = new ArrayList();

		for (int i = 0; i < cantEjemplos; i++) {
			ArrayList<Double> ej = new ArrayList();
			ej.add(-1.0 + ((double) i) / (cantEjemplos / 2));
			ejs.add(ej);
		}
		return ejs;
	}

	static ArrayList<ArrayList<Double>> crearTest(int cantEjemplos) {
		return crearEjemplos(cantEjemplos);
//		ArrayList<ArrayList<Double>> ejs = new ArrayList();
////		Random rand = new Random();
////		for (int i = 0; i < cantEjemplos; i++) {
////			ArrayList<Double> ej = new ArrayList();
////			ej.add(rand.nextDouble() * 2 - 1);
////			ejs.add(ej);
////		}
//
//		Double[] test = {-0.8126924166830887, 0.33867008779154273, 0.68290454415043, 0.8509436738705547, -0.498996505997904, 0.6035383826106704, 0.6450356055119235, -0.009564202915718356, -0.04006437023775322, 0.6705494702727617, -0.20486425430501987, -0.4636814872216637, 0.7398036267473369, -0.3497313334708654, 0.9293921859652574, 0.16518374019151572, -0.38885521494259345, 0.7978894812411876, 0.02409663532089512, 0.8722466755814862};
//		for (int i = 0; i < test.length; i++) {
//			ArrayList<Double> ej = new ArrayList();
//			ej.add(test[i]);
//			ejs.add(ej);
//		}
//
//		return ejs;
	}

	public static void main(String[] args) {
		int cantEjemplos = 20;
		int cantInput = 1;
		int cantOutput = 1;
		try {
			ArrayList<ArrayList<Double>> test = crearTest(cantEjemplos);
			BufferedWriter outIdentidad = new BufferedWriter(new FileWriter("identidad.csv"));
			BufferedWriter outxala4 = new BufferedWriter(new FileWriter("xala4.csv"));
			BufferedWriter outFuncSeno = new BufferedWriter(new FileWriter("funcSeno.csv"));

			for (int k = 0; k < 10; k++) {
				SigmoidUnit.tazaAprendizaje = 1.0 - k * 0.1;

				for (int h = 0; h < 10; h++) {
					int cantHidden = 5 + h * 5;



					outIdentidad.write(SigmoidUnit.tazaAprendizaje + "," + cantHidden + ",");
					outxala4.write(SigmoidUnit.tazaAprendizaje + "," + cantHidden + ",");
					outFuncSeno.write(SigmoidUnit.tazaAprendizaje + "," + cantHidden + ",");


					int[] posiblesIter = {10, 50, 100, 500, 1000, 10000};
					for (int t = 0; t < 6; t++) {

						String coma = ",";
						if (t == 5) {
							coma = "";
						}

						int cantIteraciones = posiblesIter[t];

						/***********************************************
						 * red neuronal para la funcion identidad
						 ***********************************************/
						RedNeuronal red = new RedNeuronal(cantInput, cantHidden, cantOutput);
						ArrayList<ArrayList<Double>> ejs = crearEjemplos(cantEjemplos);
						ArrayList<Double> salidasEjs = identidad(ejs);
						red.entrenar(ejs, salidasEjs, cantIteraciones);
						double errorPromedio = 0.0;
						for (int i = 0; i < test.size(); i++) {
							ArrayList<Double> ej = new ArrayList();
							ej.add(test.get(i).get(0));
							double error = (red.computar(ej) - test.get(i).get(0));
							errorPromedio += error*error;
						}
						errorPromedio = errorPromedio / 2;
//						System.out.println("Error promedio:" + errorPromedio);
						outIdentidad.write(errorPromedio + coma);

						/***********************************************
						 * red neuronal para la funcion x a la 4
						 ***********************************************/
						red = new RedNeuronal(cantInput, cantHidden, cantOutput);
						ejs = crearEjemplos(cantEjemplos);
						salidasEjs = xala4(ejs);
						red.entrenar(ejs, salidasEjs, cantIteraciones);
						errorPromedio = 0.0;
						for (int i = 0; i < test.size(); i++) {
							ArrayList<Double> ej = new ArrayList();
							ej.add(test.get(i).get(0));
							double error = (red.computar(ej) - test.get(i).get(0) * test.get(i).get(0) * test.get(i).get(0) * test.get(i).get(0));
							errorPromedio += error*error;
						}
						errorPromedio = errorPromedio / 2;
//						System.out.println("Error promedio:" + errorPromedio);
						outxala4.write(errorPromedio + coma);

						/***********************************************
						 * red neuronal para la funcion sin((5pi/2)x)
						 ***********************************************/
						red = new RedNeuronal(cantInput, cantHidden, cantOutput);
						ejs = crearEjemplos(cantEjemplos);
						salidasEjs = funcSeno(ejs);
						red.entrenar(ejs, salidasEjs, cantIteraciones);
						errorPromedio = 0.0;
						for (int i = 0; i < test.size(); i++) {
							ArrayList<Double> ej = new ArrayList();
							ej.add(test.get(i).get(0));
							double error = (red.computar(ej) - Math.sin(test.get(i).get(0) * (5 * Math.PI / 2)));
							errorPromedio += error*error;
						}
						errorPromedio = errorPromedio / 2;
//						System.out.println("Error promedio:" + errorPromedio);
						outFuncSeno.write(errorPromedio + coma);

					}
					outIdentidad.write("\n");
					outxala4.write("\n");
					outFuncSeno.write("\n");
					outIdentidad.flush();
					outxala4.flush();
					outFuncSeno.flush();
				}
			}
			outIdentidad.close();
			outxala4.close();
			outFuncSeno.close();
		} catch (Exception e) {//Catch exception if any
			System.err.println("Error: " + e.getMessage());
		}

	}
}
